﻿using ArtMath.Attribute;
using ArtMath.Component.Line;
using ArtMath.Component.Point;
using ArtMath.Converter;
using ArtMath.Core.Data;
using ArtMath.Core.Helper;
using ArtMath.PointCollection;
using ArtMath.Resource;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Linq;

namespace ArtMath.Component.Manager
{
    /// <summary>
    /// 角N等分线
    /// </summary>
    [Serializable]
    public class AngleNDivider : ComponentManagerBase
    {
        StraightLineBase start, end;
        int divideCnt;
        List<AngleDividerRay> lines = new List<AngleDividerRay>();
        [Browsable(false)]
        public Dictionary<AngleDividerRay, double> NewDirectedAngles { get; } = new Dictionary<AngleDividerRay, double>();
        public AngleNDivider(SketchPad pad, string name, ToolTypeName toolType, StraightLineBase start, StraightLineBase end, int n, bool addToList = true) : base(pad, name, toolType, addToList)
        {
            InitialEdge = start;
            TerminalEdge = end;
            divideCnt = n;
        }
        public override PointD MassPoint
        {
            get
            {
                return Utility.GetBaryCenter(Lines.Select((AngleDividerRay line) => { return line.MassPoint; }).ToList());
            }
        }
        PointCollectionsManager buildPCM(Func<AngleDividerRay, PointCollectionsManager> func)
        {
            if (func == null) return null;
            PointCollectionsManager res = new PointCollectionsManager(), last = null;
            foreach (AngleDividerRay item in Lines)
            {
                PointCollectionsManager current = func(item);
                res.AddPointCollection(current);
                if (last != null)
                {
                    foreach (PointCollectionBase head1 in last.PointCollections)
                    {
                        foreach (PointCollectionBase head2 in current.PointCollections)
                        {
                            res.ConnectHeads(head1, head2);
                        }
                    }
                }
                last = current;
            }
            return res;
        }
        public override PointCollectionsManager Skeleton
        {
            get
            {
                return buildPCM((AngleDividerRay ray) => { return ray.Skeleton; });
            }
        }
        public override PointCollectionsManager PSkeleton
        {
            get
            {
                return buildPCM((AngleDividerRay ray) => { return ray.PSkeleton; });
            }
        }
        public override PointCollectionsManager NewSkeleton
        {
            get
            {
                return buildPCM((AngleDividerRay ray) => { return ray.NewSkeleton; });
            }
        }
        public override PointCollectionsManager NewPSkeleton
        {
            get
            {
                return buildPCM((AngleDividerRay ray) => { return ray.NewPSkeleton; });
            }
        }
        protected override void ForEachManagedComponent(Predicate<Base> act)
        {
            if (act == null) return;
            if (!act(InitialEdge)) return;
            if (!act(TerminalEdge)) return;
        }
        [MultilingualCategory("Structure"), MultilingualDisplayName("InitialEdge")]
        public StraightLineBase InitialEdge
        {
            get { return start; }
            set
            {
                start?.ComponentManagers.Remove(this);
                start = value;
                start?.ComponentManagers.Add(this);
            }
        }
        [MultilingualCategory("Structure"), MultilingualDisplayName("TerminalEdge")]
        public StraightLineBase TerminalEdge
        {
            get { return end; }
            set
            {
                end?.ComponentManagers.Remove(this);
                end = value;
                end?.ComponentManagers.Add(this);
            }
        }
        //[MultilingualCategory("Structure"), MultilingualDisplayName("DivisionNumber")]
        //public virtual int DivideCount
        //{
        //    get { return n; }
        //    set
        //    {
        //        if (value > 1)
        //        {
        //            n = value;
        //        }
        //        else
        //        {
        //            Pad.ShowMessage(Resources.Translate("DivisionNumberLess2"), MessageType.Exclamation);
        //        }
        //    }
        //}
        [MultilingualCategory("Parameter"), MultilingualDisplayName("DivisionAngle"), TypeConverter(typeof(IntelliAngleConverter))]
        public double EachAngle
        {
            get
            {
                double delta = TerminalEdge.ArrivalAngle - InitialEdge.ArrivalAngle;
                if (delta < 0) delta += Core.Helper.Angle.RadRound;
                return delta / divideCnt;
            }
        }
        [MultilingualCategory("Parameter"), MultilingualDisplayName("DivisionRay")]
        public virtual List<AngleDividerRay> Lines
        {
            get { return lines; }
        }
        public override PointD AnchorPoint(PropertyDisplayer disp)
        {
            return Lines[0].PLocation;
        }
        public bool CheckLineNameExist(string name)
        {
            foreach (AngleDividerRay item in Lines)
            {
                if (item.Name == name)
                {
                    return true;
                }
            }
            return false;
        }
        public override void InChildrenIterator(Predicate<ShapeBase> act)
        {
            if (act == null) return;
            foreach (AngleDividerRay item in Lines)
            {
                if (item == null) continue;
                if (!act(item)) break;
            }
        }
        public override void ForEachStraightLine(Predicate<StraightLineBase> act)
        {
            if (act == null) return;
            foreach (AngleDividerRay item in Lines)
            {
                if (item == null) continue;
                if (!act(item))
                {
                    break;
                }
            }
        }
        //public double GetNewDirectedAngle(AngleDividerRay ray)
        //{
        //    int index = Lines.IndexOf(ray);
        //    return Core.Helper.Angle.StandardizeRad(InitialEdge.ArrivalAngle + (index + 1) * EachAngle);
        //}
        //public override void PointMove_Prepare(PointBase movePoint)
        //{
        //    //当角顶点不可移动时，下段代码生效
        //    foreach (AngleDividerRay item in Lines)
        //    {
        //        item.Deformation_Prepare(item.SourcePoint);
        //    }
        //}
        //public override void PointMoved_Clean(PointBase movePoint)
        //{
        //    //当角顶点不可移动时，下段代码生效
        //    foreach (AngleDividerRay item in Lines)
        //    {
        //        item.Deformation_Clean(item.SourcePoint);
        //    }
        //}
        public override void PointMoving_ManagedComponentsLimit(Base component)
        {
            NewDirectedAngles.Clear();
            double angle = InitialEdge.ArrivalAngle, each = EachAngle;
            foreach (AngleDividerRay item in Lines)
            {
                NewDirectedAngles.Add(item, angle += each);
            }
            foreach (AngleDividerRay item in Lines)
            {
                item.ExternalObjectMove(null, component);
            }
        }
        public override void CreateComponents()
        {
            PointBase pt = InitialEdge.GetCommonPoint(TerminalEdge);
            if (pt != null)
            {
                double each = EachAngle;
                for (int i = 1; i < divideCnt; i++)
                {
                    AngleDividerRay ray = new AngleDividerRay(Pad, OfTranslator2($"{Resources.GetOrdinal(i)}{Resources.Join}{Resources.Translate("DivisionRay")}"), this)
                    {
                        SourcePoint = pt,
                    };
                    if (Pad.TryCreateObject(ray))
                    {
                        ray.DirectedAngle = Core.Helper.Angle.StandardizeRad(InitialEdge.ArrivalAngle + i * each);
                        InitialEdge.OutChildren_Line.Add(ray);
                        TerminalEdge.OutChildren_Line.Add(ray);
                        Lines.Add(ray);
                    }
                }

            }
            base.CreateComponents();
        }
    }
}
